home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 001 / freedraw / freedraw.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  33KB  |  821 lines

  1. /************************************************************************/
  2. /***                FreeDraw - PD graphics for Amiga                  ***/
  3. /***                                                                  ***/
  4. /***      This is an extremely simple graphics editor which works in  ***/
  5. /***   the windowing environment of the Amiga.  It is very limited    ***/
  6. /***   in features, but I hope to add a lot more, and I would be      ***/
  7. /***   happy to receive assistance from anyone who wants to give it.  ***/
  8. /***      The basic idea of this program is to provide some minimal   ***/
  9. /***   image editing functions which can be used to develop images    ***/
  10. /***   for other programs.  I know there will be a lot of Paint type  ***/
  11. /***   type programs avaialable soon, but what are we supposed to use ***/
  12. /***   now?  The most important features to add now will probably be  ***/
  13. /***   those related to "cut and paste", disk srtorage and retrieval, ***/
  14. /***   and "single-pixel" editing like Mac's "fatbits".               ***/
  15. /***      I intend to use the IFF standard for the image storage and  ***/
  16. /***   retrieval and will be coding a "Files" menu soon.  The work    ***/
  17. /***   required for "cut and paste" should be almost trivial, but I   ***/
  18. /***   still may not get to it for a while.  Fatbits editing from one ***/
  19. /***   window to another involves some manipulations of the RastPorts ***/
  20. /***   which still elude me, as I have only recently begun to use the ***/
  21. /***   Amiga and don't yet understand some important details of these ***/
  22. /***   structures.  This would be a great item for one of the genius  ***/
  23. /***   members of the Amiga programming community to provide.         ***/
  24. /***      There are only two menu topics in this version, so using it ***/
  25. /***   is really quite easy.  Boxes are not allowed to be drawn in    ***/
  26. /***   areas outside of the window where border gadgets are located,  ***/
  27. /***   and the pen-draw mode also clips to these same boundaries.  If ***/
  28. /***   you have begun to draw a box by clicking the left button while ***/
  29. /***   the cursor is located in the FreeDraw window, then you can     ***/
  30. /***   cancel that box by clicking the right button.  In the pen mode ***/
  31. /***   pressing and holding the left button will draw.   Colors are   ***/
  32. /***   selected by simply releasing the menu button over the desired  ***/
  33. /***   color in the Color menu.   The erase feature always clears the ***/
  34. /***   window to the currently selected color.                        ***/
  35. /***      This is no gem of programming style, but you're getting it  ***/
  36. /***   for the right price so be patient with its design flaws.  New  ***/
  37. /***   versions will appear here on BIX as soon as I can get them in  ***/
  38. /***   shape for release.  I apologize to anyone who objects to my    ***/
  39. /***   lack of coding grace, but I just want to get the project off   ***/
  40. /***   the ground, and improvements will be forthcoming.  There are   ***/
  41. /***   a lot of comments, but I didn't know what needed to be made    ***/
  42. /***   clear so I just commented everything.                          ***/
  43. /***                                                                  ***/
  44. /***      If you like the idea of a PD graphics program and would be  ***/
  45. /***   interested in doing some development work, then please write   ***/
  46. /***   me at the address listed below, or call if you prefer.  I do   ***/
  47. /***   want to know if there is any interest in such a project, so    ***/
  48. /***   I will be glad to discuss any ideas you might have.  Also, as  ***/
  49. /***   I do not currently use CompuServe or any other major nets, I   ***/
  50. /***   would appreciate if someone would post this listing there.     ***/
  51. /***      I hope somebody enjoys this.  Have Fun.                     ***/
  52. /***                                           Rick Ross 11/14/85     ***/
  53. /***                                                                  ***/
  54. /***        My address:                                               ***/
  55. /***                    Richard M. Ross, Jr.                          ***/
  56. /***                    Eidetic Imaging                               ***/
  57. /***                    740 N. 22nd Street                            ***/
  58. /***                    Philadelphia, PA  19130                       ***/
  59. /***                                                                  ***/
  60. /***                    Phone - (215) 236-7388                        ***/
  61. /************************************************************************/
  62.  
  63. /*  compiler directives to fetch the necessary header files */
  64.  
  65. #include <exec/types.h>
  66. #include <exec/exec.h>
  67. #include <intuition/intuition.h>
  68. #include <intuition/intuitionbase.h>
  69. #include <graphics/gfx.h>
  70. #include <graphics/regions.h>
  71. #include <graphics/copper.h>
  72. #include <graphics/gels.h>
  73. #include <graphics/gfxbase.h>
  74. #include <devices/keymap.h>
  75. #include <hardware/blit.h>
  76.  
  77. /*   These definitions are used by intuition for
  78.  *   calls to OpenLibrary() in order to ensure
  79.  *   that an appropriate ROM revision is
  80.  *   available.
  81.  */
  82.  
  83. #define INTUITION_REV 1
  84. #define GRAPHICS_REV  1
  85.  
  86. /*   Intuition always wants to see these declarations */
  87. struct IntuitionBase *IntuitionBase;
  88. struct GfxBase *GfxBase;
  89.  
  90. /*   This is the Window structure declaration.
  91.  *   Nothing fancy is going on here, but note
  92.  *   the Flags and IDCMPFlags members of the
  93.  *   structure define which messages will be
  94.  *   sent by Intuition.  I haven't used them all
  95.  *   and if you want to change the settings you
  96.  *   should probably do it her instead of using
  97.  *   ModifyIDCMP later.
  98.  */
  99.  
  100. struct NewWindow NewWindow = {
  101.    20,
  102.    20,
  103.    300,
  104.    150,
  105.    0,
  106.    1,
  107.    CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK
  108.    | NEWSIZE | INACTIVEWINDOW | SIZEVERIFY,
  109.    WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG
  110.    | WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE,
  111.    NULL,
  112.    NULL,
  113.    "AMIGA FreeDraw 0.01",
  114.    NULL,
  115.    NULL,
  116.    100, 35,
  117.    640, 200,
  118.    WBENCHSCREEN,
  119. };
  120.  
  121. /*******************************************************************/
  122. /*      DrawBox - Simple routine to draw an unfilled rectangle     */
  123. /*   It accepts the  coordinates of the top-left and lower-right   */
  124. /*   points of the rectangle, a pointer to the Window structure,   */
  125. /*   and the color in which to render the rectangle.  The current  */
  126. /*   FgPen color of the window is preserved thru the call.  No     */
  127. /*   clipping is done.                                             */
  128. /*******************************************************************/
  129. void DrawBox( tlx, tly, brx, bry, window, color )
  130. SHORT tlx, tly;                  /* top-left x,y coordinates */
  131. SHORT brx, bry;                  /* lower-right x,y coordinates */
  132. struct Window *window;           /* pointer to target window */
  133. BYTE color;                      /* color to use for render */
  134.    {
  135.    BYTE OldColor = window->RPort->FgPen;   /* save window's FgPen */
  136.  
  137.    SetAPen( window->RPort, color );        /* set draw color for box  */
  138.    Move(window->RPort, tlx, tly);          /* move to top-left point  */
  139.    Draw(window->RPort, brx, tly);          /* and draw to each of the */
  140.    Draw(window->RPort, brx, bry);          /* four corners of the box */
  141.    Draw(window->RPort, tlx, bry);
  142.    Draw(window->RPort, tlx, tly);
  143.    SetAPen( window->RPort, OldColor );     /* restore old FgPen */
  144.    }
  145.  
  146.  
  147. /*********************************************************/
  148. /*                 Color Select Menu                     */
  149. /*                                                       */
  150. /*      This is where the menu for color selection is    */
  151. /*   defined.  It should be flexible enough to allow for */
  152. /*   increased palette sizes, but this version is only   */
  153. /*   for the 4-color mode of the WorkBench screen.       */
  154. /*********************************************************/
  155.  
  156. /*   A few definitions are needed here.
  157.  *   Note that MAXPAL should be increased
  158.  *   to allow for palette larger than
  159.  *   four colors.    
  160.  */
  161. #define ITEMSTUFF (ITEMENABLED | HIGHBOX)
  162. #define CW 40
  163. #define CH 25
  164. #define MAXPAL 4
  165.  
  166. /*   declare enough storage for required
  167.  *   number of menu items and associated
  168.  *   images.  This menu will be using
  169.  *   graphics renditions of menu items,
  170.  *   so the Image structures must be
  171.  *   declared.  This menu is modeled after
  172.  *   the one found in the IconEd source.
  173.  */
  174. struct MenuItem coloritem[MAXPAL];
  175. struct Image colorimage[MAXPAL];
  176.  
  177. /*   array of palette sizes to correspond with
  178.  *   depth of window in bit-planes
  179.  */
  180. SHORT palette[] = { 2, 4, 8, 16, 32 };
  181.  
  182.  
  183. /*****************************************************************/
  184. /*    The following function initializes the structure arrays    */
  185. /*   needed to provide the Color menu topic.                     */
  186. /*****************************************************************/
  187. InitColorItems( depth )
  188. SHORT depth;               /* number of bit-planes in window */
  189.    {
  190.    SHORT n, colors;
  191.  
  192.    colors = palette[depth-1];
  193.    for( n=0; n<colors; n++ )           /* loop for max number of items */
  194.       {
  195.       coloritem[n].NextItem = &coloritem[n+1];
  196.       coloritem[n].ItemFill = (APTR)&colorimage[n];
  197.       /*   the next two items might be changed for
  198.        *   when bit-planes is greater than 2
  199.        */
  200.       coloritem[n].LeftEdge = 2 + CW * (n % 4);
  201.       coloritem[n].TopEdge = CH * (n / 4);
  202.       coloritem[n].Width = CW;
  203.       coloritem[n].Height = CH;
  204.       coloritem[n].Flags = ITEMSTUFF;
  205.       coloritem[n].MutualExclude = 0;
  206.       coloritem[n].SelectFill = NULL;
  207.       coloritem[n].Command = 0;
  208.       coloritem[n].SubItem = NULL;
  209.       coloritem[n].NextSelect = 0;
  210.  
  211.       colorimage[n].LeftEdge = 1;
  212.       colorimage[n].TopEdge = 1;
  213.       colorimage[n].Width = CW-2;
  214.       colorimage[n].Height = CH-2;
  215.       colorimage[n].Depth = depth;
  216.       colorimage[n].ImageData = NULL;
  217.       colorimage[n].PlanePick = 0;
  218.       colorimage[n].PlaneOnOff = n;
  219.       }
  220.    coloritem[colors-1].NextItem = NULL;   /* needed for last item in list */
  221.    return( 0 );
  222.    }
  223.  
  224.  
  225. /*****************************************************/
  226. /*                Draw Mode Menu                     */
  227. /*                                                   */
  228. /*      Here are the code and data declarations for  */
  229. /*   the DrawMode menu.  Current choices are limited */
  230. /*   to Erase, Filled Box, Hollow Box, and PenDraw.  */
  231. /*****************************************************/
  232.  
  233. /* define maximum number of menu items */
  234. #define DMODEMAX 4
  235.  
  236. /*   declare storage space for menu items and
  237.  *   their associated IntuiText structures
  238.  */
  239. struct MenuItem DModeItem[DMODEMAX];
  240. struct IntuiText DModeText[DMODEMAX];
  241.  
  242. /*****************************************************************/
  243. /*    The following function initializes the structure arrays    */
  244. /*   needed to provide the DrawMode menu topic.                  */
  245. /*****************************************************************/
  246. InitDModeItems()
  247.    {
  248.    short n;
  249.  
  250.    /* initialize each meu item and IntuiText with loop */
  251.    for( n=0; n<DMODEMAX; n++ )
  252.       {
  253.       DModeItem[n].NextItem = &DModeItem[n+1];
  254.       DModeItem[n].LeftEdge = 0;
  255.       DModeItem[n].TopEdge = 10 * n;
  256.       DModeItem[n].Width = 112;
  257.       DModeItem[n].Height = 10;
  258.       DModeItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
  259.       DModeItem[n].MutualExclude = 0;
  260.       DModeItem[n].ItemFill = (APTR)&DModeText[n];
  261.       DModeItem[n].SelectFill = NULL;
  262.       DModeItem[n].Command = 0;
  263.       DModeItem[n].SubItem = NULL;
  264.       DModeItem[n].NextSelect = 0;
  265.  
  266.       DModeText[n].FrontPen = 0;
  267.       DModeText[n].BackPen = 1;
  268.       DModeText[n].DrawMode = JAM2;     /* render in fore and background */
  269.       DModeText[n].LeftEdge = 0;
  270.       DModeText[n].TopEdge = 1;
  271.       DModeText[n].ITextFont = NULL;
  272.       DModeText[n].NextText = NULL;
  273.       }
  274.    DModeItem[DMODEMAX-1].NextItem = NULL;
  275.  
  276.    /* initialize text for specific menu items */
  277.    DModeText[0].IText = (UBYTE *)"Erase All";
  278.    DModeText[1].IText = (UBYTE *)"Hollow Box";
  279.    DModeText[2].IText = (UBYTE *)"Filled Box";
  280.    DModeText[3].IText = (UBYTE *)"Pen Draw";
  281.  
  282.    return( 0 );
  283.    }
  284.  
  285.  
  286. /***************************************************/
  287. /*                Menu Definition                  */
  288. /*                                                 */
  289. /*      This section of code is where the simple   */
  290. /*   menu definition goes.  For now it supports    */
  291. /*   only Color and Drawmode selection, but new    */
  292. /*   choices can easily be added by creating       */
  293. /*   structures and initializations functions      */
  294. /*   similar to those provided above.              */
  295. /***************************************************/
  296.  
  297. /* current number of available menu topics */
  298. #define MAXMENU 2
  299.  
  300. /*   declaration of menu structure array for
  301.  *   number of current topics.  Intuition
  302.  *   will use the address of this array to
  303.  *   set and clear the menus associated with
  304.  *   the window.
  305.  */
  306. struct Menu menu[MAXMENU];
  307.  
  308. /**********************************************************************/
  309. /*   The following function initializes the Menu structure array with */
  310. /*  appropriate values for our simple menu strip.  Review the manual  */
  311. /*  if you need to know what each value means.                        */
  312. /**********************************************************************/
  313. InitMenu()
  314.    {
  315.    menu[0].NextMenu = &menu[1];
  316.    menu[0].LeftEdge = 10;
  317.    menu[0].TopEdge = 0;
  318.    menu[0].Width = 50;
  319.    menu[0].Height = 10;
  320.    menu[0].Flags = MENUENABLED;
  321.    menu[0].MenuName = "Color";           /* text for menu-bar display */
  322.    menu[0].FirstItem = &coloritem[0];    /* pointer to first item in list */
  323.  
  324.    menu[1].NextMenu = NULL;
  325.    menu[1].LeftEdge = 65;
  326.    menu[1].TopEdge = 0;
  327.    menu[1].Width = 85;
  328.    menu[1].Height = 10;
  329.    menu[1].Flags = MENUENABLED;
  330.    menu[1].MenuName = "DrawMode";        /* text for menu-bar display */
  331.    menu[1].FirstItem = &DModeItem[0];    /* pointer to first item in list */
  332.  
  333.    return( 0 );
  334.    }
  335.  
  336.  
  337. /******************************************************/
  338. /*                   Main Program                     */
  339. /*                                                    */
  340. /*      This is the main body of the program.         */
  341. /******************************************************/
  342.  
  343. main()
  344.    {
  345.    struct Window *Window;              /* ptr to applications window */
  346.    struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
  347.    BYTE DrawColor = 1;                 /* initial drawing color */
  348.    SHORT OldBRX = 30, OldBRY = 30;     /* point coords used for boxes */
  349.    SHORT TLX = 20, TLY = 20;           /* initial top-left point coords */
  350.    ULONG class;                        /* used in message monitor loop */
  351.    USHORT code;                        /* used in message monitor loop */
  352.    SHORT x, y, x1, y1, x2, y2;         /* various coordinate variables */
  353.    SHORT MinX, MinY, MaxX, MaxY;       /* clipping boundary variables */
  354.    USHORT MenuNum, ItemNum;
  355.  
  356.    /*   The following is a set of declarations
  357.     *   for a number of flag values used by the
  358.     *   program.  These would perhaps be better
  359.     *   coded as a bit-field for all the flags,
  360.     *   but I'm lazy, and this is easier.
  361.     */
  362.    SHORT MouseMoved = FALSE;     /* indicates new mouse position ready */
  363.    SHORT KeepGoing = TRUE;       /* main loop control value */
  364.    SHORT ClipIt = FALSE;         /* are new point coords out of bounds? */
  365.    SHORT ClippedLast = FALSE;    /* was last PenDraw operation clipped? */
  366.    SHORT PenMode = FALSE;        /* indicates PenDraw mode is set */      
  367.    SHORT PenDown = FALSE;        /* if mouse moved, then should it draw? */
  368.    SHORT RubberBox = FALSE;      /* are we currently rubberbanding a box? */
  369.    SHORT FilledBox = FALSE;      /* should boxes be filled when drawn? */
  370.  
  371.    /* attempt to Open Library to access Intuition */
  372.    IntuitionBase = (struct IntuitionBase *)
  373.       OpenLibrary("intuition.library", INTUITION_REV);
  374.    if( IntuitionBase == NULL )
  375.       exit(FALSE);
  376.  
  377.    /* attempt to OpenLibrary to access Graphics functions */
  378.    GfxBase = (struct GfxBase *)
  379.       OpenLibrary("graphics.library",GRAPHICS_REV);
  380.    if( GfxBase == NULL )
  381.       exit(FALSE);
  382.  
  383.  
  384.    /* Try to open new window for application */
  385.    if(( Window = (struct Window *)OpenWindow(&NewWindow) ) == NULL)
  386.       exit(FALSE);
  387.  
  388.    /*   set initial clipping boundaries
  389.     *   from the values found in the window
  390.     *   structure for border dimensions
  391.     */
  392.    MinX = Window->BorderLeft;
  393.    MinY = Window->BorderTop;
  394.    MaxX = Window->Width - Window->BorderRight - 1;
  395.    MaxY = Window->Height - Window->BorderBottom - 1;
  396.  
  397.    InitColorItems( 2 );         /* initialize Color menu arrays */
  398.    InitDModeItems();            /* initialize DrawMode menu arrays */
  399.    InitMenu();                  /* initialize the menu structures */
  400.  
  401.    /*   Now, having initialized the various arrays
  402.     *   of structures required for menu generation
  403.     *   we can tell Intuition to make our menus
  404.     *   available to the user when this window
  405.     *   is active.
  406.     */
  407.    SetMenuStrip( Window, &menu[0] );
  408.  
  409.    /* set initial drw mode and color */
  410.    SetDrMd( Window->RPort, JAM1 );
  411.    SetAPen( Window->RPort, DrawColor );
  412.  
  413.    /*   Everything the program needs is now
  414.     *   initialized and put in place.  The
  415.     *   program enters the following loop
  416.     *   and processes message continuously as
  417.     *   they are received from Intuition.
  418.     *      I guess this loop is the real workhorse
  419.     *   of the program.  By the way, the loop
  420.     *   control variable KeepGoing remains TRUE
  421.     *   until a CLOSEWINDOW message is received.
  422.     *   At that point it goes FALSE, and the
  423.     *   program cleans up and exits.
  424.     */
  425.    while( KeepGoing )
  426.       {
  427.  
  428.       /* stay here until a message is received from Intuition */
  429.       Wait( 1 << Window->UserPort->mp_SigBit);
  430.  
  431.       MouseMoved = FALSE;    /* clear this flag each time thru loop */
  432.  
  433.       /*   since more than one message may be waiting
  434.        *   a reply at this point, a loop is used to
  435.        *   process all that have come in until no more
  436.        *   are ready.  Msg received is assigned to
  437.        *   NewMessage from the GetMsg() function.  This
  438.        *   value will be NULL if no message is ready,
  439.        *   and control passes out of the loop at that time
  440.        */
  441.       while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
  442.          {
  443.  
  444.          /*   copy some values from the message structure
  445.           *   to variables used in the switch statements
  446.           *   below
  447.           */
  448.          class = NewMessage->Class;
  449.          code = NewMessage->Code;
  450.          x = Window->MouseX;
  451.          y = Window->MouseY;
  452.  
  453.          /*   SIZEVERIFY is a very high priority message
  454.           *   in our loop and requires some immediate
  455.           *   servicing.  Any outstanding draw operations
  456.           *   are immediately cancelled, and the DrawMode
  457.           *   is nulled.  This prevents any attempts to
  458.           *   render outside whatever new Window boundaries
  459.           *   the user chooses.
  460.           */
  461.          if( class == SIZEVERIFY )
  462.             {
  463.             PenDown = FALSE;
  464.             if( RubberBox )
  465.                {
  466.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  467.                Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  468.                RubberBox = FALSE;
  469.                }
  470.             }
  471.  
  472.          /*   we have all the information needed from
  473.           *   the message, so we can now safely reply
  474.           *   to it without losing data
  475.           */
  476.          ReplyMsg( NewMessage );
  477.  
  478.          /*  Examine point coords from message received
  479.           *  and set the clipping flag if out of bounds.
  480.           *  If user was drawing in PenMode when message
  481.           *  was received, then the ClippedLast flag
  482.           *  should also be set to indicate this to the
  483.           *  next draw operation.
  484.           */
  485.          if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY ))
  486.             if( PenDown )
  487.                ClippedLast = TRUE;
  488.  
  489.  
  490.          /* enter switch on type of message received */
  491.          switch( class )
  492.          {
  493.             case MOUSEMOVE:
  494.                /*   Don't really do anything with this one
  495.                 *   until any other, more important, messages
  496.                 *   are received and processed.
  497.                 */
  498.                MouseMoved = TRUE;
  499.                break;
  500.  
  501.             case NEWSIZE:
  502.                /*  set new clipping boundaries */
  503.                MinX = Window->BorderLeft;
  504.                MinY = Window->BorderTop;
  505.                MaxX = Window->Width - Window->BorderRight - 1;
  506.                MaxY = Window->Height - Window->BorderBottom - 1;
  507.                break;
  508.  
  509.             case CLOSEWINDOW:
  510.                /*   User is ready to quit, so indicate
  511.                 *   that execution should terminate
  512.                 *   with next iteration of the loop.
  513.                 */
  514.                KeepGoing = FALSE;
  515.                break;
  516.  
  517.             case MOUSEBUTTONS:
  518.                /*   A number of things could have happened
  519.                 *   here, and further examination of data
  520.                 *   received from message is needed to
  521.                 *   determine what action should be taken.
  522.                 *   The code variable holds important info
  523.                 *   about what actually caused the message
  524.                 *   to be sent in the first place.
  525.                 */
  526.                switch ( code )
  527.                   {
  528.                   case SELECTUP:
  529.                      /*   User was holding down the left button
  530.                       *   and just released it.  The PenMode
  531.                       *   flag variables are set accordingly.
  532.                       *   The pen can no longer be down, and
  533.                       *   ClippedLast is reset for next time.
  534.                       */
  535.                      PenDown = ClippedLast = FALSE;
  536.                      break;
  537.  
  538.                   case SELECTDOWN:
  539.                      /*   User has pressed the left button, and
  540.                       *   several differnt actions may need to
  541.                       *   be taken.  If the ClipIt value is TRUE,
  542.                       *   then no action should be taken at all.
  543.                       */
  544.                      if( ClipIt )
  545.                         break;
  546.  
  547.                      /*   If user is currently in PenMode, then
  548.                       *   set up to draw when MOUSEMOVED messages
  549.                       *   are received until a subsequent SELECTUP
  550.                       *   message comes in.
  551.                       */
  552.                      if( PenMode )
  553.                         {
  554.                         PenDown = TRUE;
  555.                         ClippedLast = FALSE;
  556.  
  557.                         /* make sure to set appropriate mode */
  558.                         SetDrMd( Window->RPort, JAM1 );
  559.  
  560.                         /* and establish initial position to draw */
  561.                         Move( Window->RPort, x, y );
  562.                         break;
  563.                         }
  564.  
  565.                      /*   If user is currently rubberbanding a box,
  566.                       *   then a SELECTDOWN message means it is time
  567.                       *   to stop rubberbanding and actually draw it.
  568.                       *   The following code will be executed if
  569.                       *   this is the case, and it will determine if
  570.                       *   a filled box is needed before rendering.
  571.                       */
  572.                      if( RubberBox )
  573.                         {
  574.                         /*   set draw mode back to JAM1 since
  575.                          *   it is now currently set to COMPLEMENT
  576.                          */
  577.                         SetDrMd( Window->RPort, JAM1 );
  578.                         RubberBox = FALSE;   /* turn off rubberbanding */
  579.  
  580.                         /*   Restore the condition of the RMBTRAP
  581.                          *   bit in the Window structure's Flags
  582.                          *   member.  Menubutton events will no
  583.                          *   be received by this loop.
  584.                          */
  585.                         Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  586.  
  587.                         /*   RectFill is not condusive to the smooth
  588.                          *   execution of programs iit arguments are
  589.                          *   out of order, sot his code sorts them
  590.                          *   in preparation for the call.
  591.                          */
  592.                         if( FilledBox )
  593.                            {
  594.                            /* first sort the x-coords */
  595.                            if( TLX < OldBRX )  {
  596.                               x1 = TLX;  x2 = OldBRX;  }
  597.                            else  {
  598.                               x1 = OldBRX;  x2 = TLX;  }
  599.  
  600.                            /* then sort the y-coords */
  601.                            if( TLY < OldBRY )  {
  602.                               y1 = TLY;  y2 = OldBRY;  }
  603.                            else  {
  604.                               y1 = OldBRY;  y2 = TLY;  }
  605.  
  606.                            /* now generate the filled rectangle */
  607.                            RectFill( Window->RPort, x1, y1, x2, y2 );
  608.                            }
  609.                         else
  610.                            {
  611.                            /* FilledBox not set, so draw hollow box */
  612.                            DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  613.                            }
  614.                         break;
  615.                         }
  616.  
  617.                      /*   If execution comes here, then PenMode was
  618.                       *   not set and user was not rubberbanding.
  619.                       *   SELECTDOWN therefore indicates to start the
  620.                       *   rubberbanding process at this point.  The
  621.                       *   initial coords are set to the values we
  622.                       *   received when the GetMsg() was executed.
  623.                       */
  624.                      TLX = OldBRX = x;  TLY = OldBRY = y;
  625.  
  626.                      /* set to render in XOR mode */
  627.                      SetDrMd( Window->RPort, COMPLEMENT );
  628.  
  629.                      /* set flag to indicate we are now rubberbanding */
  630.                      RubberBox = TRUE;
  631.  
  632.                      /*   This instruction indicates to Intuition
  633.                       *   that we now wish to receive a message
  634.                       *   each time the Menubutton is pressed.
  635.                       *   This is how we hijack the right button
  636.                       *   for temporary use as a Cancel button
  637.                       *   instead of a Menubutton.
  638.                       */
  639.                      Window->Flags |= RMBTRAP;
  640.  
  641.                      /* render the initial rubberbox and exit */
  642.                      DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  643.                      break;
  644.  
  645.                   case MENUDOWN:
  646.                      /*   WE only receive this message class if
  647.                       *   the RMBTRAP flag bit has been set, so
  648.                       *   it always means that we should cancel
  649.                       *   the box which is currently rubberbanding.
  650.                       */
  651.                      /* turn the flag off */
  652.                      RubberBox = FALSE;
  653.  
  654.                      /* restore control of menubutton to Intuition */
  655.                      Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  656.  
  657.                      /*   erase (by double XOR'ing) the current
  658.                       *   rubberbox and exit switch.
  659.                       */
  660.                      DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  661.                      break;
  662.  
  663.                   default:
  664.                      /*   Something unimportant happened, so just
  665.                       *   continue thru the GetMsg() loop.
  666.                       */
  667.                      continue;
  668.                }
  669.                break;
  670.  
  671.             case MENUPICK:
  672.                /*   A menu event has taken place and is
  673.                 *   ready to be processed.  Examine the
  674.                 *   code variable received from the message
  675.                 *   to determine what action should be taken.
  676.                 *   The first check is for MENUNULL, which
  677.                 *   means that nothing should be done at all.
  678.                 */
  679.                if( code != MENUNULL )
  680.                   {
  681.                   /* get menu and item numbers from code */
  682.                   MenuNum = MENUNUM( code );
  683.                   ItemNum = ITEMNUM( code );
  684.  
  685.                   /* determine appropriate action by menu number */
  686.                   switch ( MenuNum )
  687.                      {
  688.                      case 0:
  689.                         /*   Menu 0 is the Color menu.  The
  690.                          *   item number indicates which new
  691.                          *   color to set.
  692.                          */
  693.                         DrawColor = ItemNum;
  694.                         SetAPen( Window->RPort, DrawColor );
  695.                         break;
  696.  
  697.                      case 1:
  698.                         /*   Menu 1 is the DrawMode menu.  The item
  699.                          *   number indicates what to do.
  700.                          *   NOTE:  Since we cannot have received
  701.                          *   this message if we were rubberbanding,
  702.                          *   then there is no need to clean up before
  703.                          *   changing drawing modes.
  704.                          */
  705.                         switch ( ItemNum )
  706.                            {
  707.                            case 0:
  708.                               /* Erase window to current color */
  709.                               SetDrMd( Window->RPort, JAM1 );
  710.                               RectFill( Window->RPort, MinX,MinY,MaxX,MaxY);
  711.                               break;
  712.  
  713.                            case 1:
  714.                               /* set flag variables for hollow box */
  715.                               PenMode = FALSE;
  716.                               FilledBox = FALSE;
  717.                               break;
  718.  
  719.                            case 2:
  720.                               /* set flag variables for filled box */
  721.                               PenMode = FALSE;
  722.                               FilledBox = TRUE;
  723.                               break;
  724.  
  725.                            case 3:
  726.                               /* set flag variables for PenMode */
  727.                               PenMode = TRUE;
  728.                               break;
  729.  
  730.                            default:
  731.                               /* don't do anything */
  732.                               break;
  733.                            }
  734.                         break;
  735.  
  736.                      default:
  737.                         /* Menu number unrecognized, do nothing */
  738.                         break;
  739.                      }
  740.                   }
  741.                break;
  742.  
  743.             case INACTIVEWINDOW:
  744.                /*   User has de-selected our window, so a
  745.                 *   little bit of cleaning up may be needed
  746.                 *   to prevent untoward events when he comes
  747.                 *   back to it.
  748.                 */
  749.                /* erase any outstanding rubberbox */
  750.                if( RubberBox )
  751.                   DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  752.  
  753.                /* reset all the flafg variables */
  754.                PenDown = ClippedLast = RubberBox = FALSE;
  755.  
  756.                /* return possibly diverted menubutton events to Big I */
  757.                Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  758.                break;
  759.  
  760.             default:
  761.                /* message class was unrecognized, so do nothing */
  762.                break;
  763.             }
  764.          }   /* this brace ends the while(NewMessage) loop way back when */
  765.  
  766.       /*   There are no more messages waiting at the
  767.        *   IDCMP port, so we can now proceed to
  768.        *   process any MOUSEMOVED message we may
  769.        *   have received.
  770.        */
  771.       if( MouseMoved && !ClipIt)
  772.          {
  773.          /* the mouse did move, and we don't need to clip */
  774.  
  775.          /* check first if we are drawing in PenMode */
  776.          if( PenDown )
  777.             {
  778.             /*   We have to examine if we clipped the
  779.              *   last PenMode draw operation.  If we did,
  780.              *   then this is the first move back into
  781.              *   window boundaries, so we mov instead of
  782.              *   drawing.
  783.              */
  784.             if( ClippedLast )
  785.                {
  786.                ClippedLast = FALSE;         /* reset this flag now */
  787.                Move( Window->RPort, x, y );
  788.                }
  789.             else
  790.                Draw( Window->RPort, x, y ); /* draw to x,y coords */
  791.          }
  792.          else
  793.             {
  794.             /*   We weren't in PenMode, but we still might
  795.              *   be rubberbanding a box.  If so, then we
  796.              *   should erase the current rubberbox and
  797.              *   draw a new one with the new mouse coords.
  798.              */
  799.             if( RubberBox )
  800.                {
  801.                /* erase the old rubberbox - draw mode is COMPLEMENT */
  802.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  803.  
  804.                /* assign new values to box coords */
  805.                OldBRX = x;  OldBRY = y;
  806.  
  807.                /* and draw the new rubberbox */ 
  808.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  809.                }
  810.             }
  811.          }
  812.       }
  813.  
  814.    /*   It must be time to quit, so we have to clean
  815.     *   up and exit.
  816.     */
  817.    ClearMenuStrip( Window );
  818.    CloseWindow( Window );
  819.    exit(TRUE);
  820.    }
  821.